﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>linq.js tutorial</title>
    <script type="text/javascript" src="../linq.js"></script>
    <script type="text/javascript">
        var textStack = [];
        document.write = function () {
            Enumerable.from(arguments).forEach("textStack.push($)");
        };
        document.writeln = function () {
            Enumerable.from(arguments).forEach("textStack.push($)");
        };

        window.onload = function ()
        {
            Enumerable.from(document.getElementsByTagName("pre"))
                .forEach(function (ele)
                {
                    eval(ele.innerText || ele.textContent);
                    var p = document.createElement("p");
                    p.innerHTML = textStack.join("");
                    ele.appendChild(p);
                    textStack.length = 0;
                });
        }
    </script>
</head>
<body>
    <h2>
        First step of Lambda Expression</h2>
    <pre>
    // Anonymous function
    Enumerable.range(1, 3).select(function(value, index) { return index + ':' + value }).writeLine();
    // String like Lambda Expression (arguments => expression)
    Enumerable.range(1, 3).select("value,index=>index+':'+value").writeLine();
    
    // If the number of arguments is one , can use default iterator variable '$'
    Enumerable.range(1, 3).select("i=>i*2").writeLine();
    Enumerable.range(1, 3).select("$*2").writeLine(); // same
    
    // "" is shortcut of "x => x" (identity function)
    Enumerable.range(4, 7).join(Enumerable.range(8, 5), "", "", "outer,inner=>outer*inner").writeLine();
    </pre>
    <h2>
        Scope of lambda expression</h2>
    <pre>
    var number = 3;
    // Can't Find number | lambda expression can use only global variable
    // Enumerable.range(1,10).where("$ == number").writeLine();

    // use anonymous founction, can capture variable
    Enumerable.range(1,10).where(function(i){return i == number}).writeLine();
    </pre>
    <h2>
        from(Object) -> convert to KeyValuePair</h2>
    <pre>
    var object = {foo:"a", "bar":100, "foobar":true};
    Enumerable.from(object).forEach(function(obj)
    {
        document.write(obj.key + ":" + obj.value + "&lt;br />");
    })
    </pre>
    <h2>
        forEach (continue and break)</h2>
    <pre>
    Enumerable.repeat("foo", 10).forEach(function(value, index)
    {
        if (index % 2 == 0) return; // continue
        if (index > 6) return false; // break
        document.write(index + ":" + value + "&lt;br />");
    });
    </pre>
    <h2>
        Grouping and ref/value compare</h2>
    <pre>
    // ref compare
    document.write((new Date(2000, 1, 1) == new Date(2000, 1, 1)) + "&lt;br />"); // false
    document.write(({ a: 0} == { a: 0 }) + "&lt;br />"); // false
    
    document.write("------" + "&lt;br />");
    var objects = [
        { Date: new Date(2000, 1, 1), Id: 1 },
        { Date: new Date(2010, 5, 5), Id: 2 },
        { Date: new Date(2000, 1, 1), Id: 3 }
    ]

    // ref compare, can not grouping
    Enumerable.from(objects)
        .groupBy("$.Date", "$.Id",
            function (key, group) { return { date: key, ids: group.toJoinedString(',')} })
        .writeLine("$.date + ':' + $.ids");

    document.write("------" + "&lt;br />");

    // use fourth argument(compareSelector)
    Enumerable.from(objects)
        .groupBy("$.Date", "$.Id",
            function (key, group) { return { date: key, ids: group.toJoinedString(',')} },
            function (key) { return key.toString() })
        .writeLine("$.date + ':' + $.ids");
        </pre>
    <h2>
        Regular Expression Matches</h2>
    <pre>
    // Enumerable.matches return Enumerable&lt;MatchObject>

    var input = "abcdefgABzDefabgdg";
    Enumerable.matches(input, "ab(.)d", "i").forEach(function(match)
    {
        for (var prop in match)
        {
            document.write(prop + " : " + match[prop] + "&lt;br />");
        }
        document.write("toString() : " + match.toString() + "&lt;br />");
        document.write("---" + "&lt;br />");
    });
    </pre>
    <h2>
        LazyEvaluation and InfinityList</h2>
    <pre>
    // first radius of circle's area over 10000
    var result = Enumerable.toInfinity(1).where("r=>r*r*Math.PI>10000").first();
    document.write(result);
    </pre>
    <h2>
        Dictionary</h2>
    <pre>
    // sample class
    var cls = function (a, b)
    {
        this.a = a;
        this.b = b;
    }
    var instanceA = new cls("a", 100);
    var instanceB = new cls("b", 2000);

    // create blank dictionary
    var dict = Enumerable.empty().toDictionary();
    // create blank dictionary(use compareSelector)
    var dict = Enumerable.empty().toDictionary("","",function (x) { return x.a + x.b });

    dict.add(instanceA, "zzz");
    dict.add(instanceB, "huga");
    document.write(dict.get(instanceA) + "&lt;br />"); // zzz
    document.write(dict.get(instanceB) + "&lt;br />"); // huga

    // enumerable (to KeyValuePair)
    dict.toEnumerable().forEach(function (kvp)
    {
        document.write(kvp.key.a + ":" + kvp.value + "&lt;br />");
    });
    </pre>
    <h2>
        sample - Nondeterministic Programs</h2>
    // from Structure and Interpretation of Computer Programs 4.3.2
    <pre>
    var apart = Enumerable.range(1, 5);
    var answers = apart
        .selectMany(function(baker){ return apart
        .selectMany(function(cooper){ return apart
        .selectMany(function(fletcher){ return apart
        .selectMany(function(miller){ return apart
        .select(function(smith){ return {
            baker: baker, cooper: cooper, fletcher: fletcher, miller: miller, smith: smith}})})})})})
        .where(function(x){ return Enumerable.from(x).distinct("$.value").count() == 5 })
        .where("$.baker != 5")
        .where("$.cooper != 1")
        .where("$.fletcher != 1 && $.fletcher != 5")
        .where("$.miller > $.cooper")
        .where("Math.abs($.smith - $.fletcher) != 1")
        .where("Math.abs($.fletcher - $.cooper) != 1");

    answers.selectMany().writeLine("$.key + ':' + $.value");
    </pre>
</body>
</html>
